/// <remarks>
/// AddFiles Class
/// This form list all files under the selected directory and add the
/// to the selected project.
/// 
/// Authors: Georges Marceau, Matricis Informatique Inc.
///          Louis-Philippe Lebouthillier.
/// </remarks>

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Common;
using Microsoft.TeamFoundation.VersionControl.Client;
using VcLib;

namespace VcGUI
{
    public partial class AddFilesFrm : Form
    {
        private Logger logger = Logger.Instance;
        private VcLib.TFSFacade VcUtil = VcLib.TFSFacade.Instance;
        private ImageList imageList1 = new ImageList();
        private ImageList smallImageList = new ImageList();
        private string projectPath;

        public AddFilesFrm(string project, string localPath)
        {
            InitializeComponent();            

            this.projectPath = localPath;
            this.txtFolder.Text = localPath;
            this.txtProject.Text = project;
            this.AcceptButton = this.btnOK;
            this.CancelButton = this.btnCancel;
            RefreshList();
        }

        private void btnBrowse_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog fbdlg = new FolderBrowserDialog();
            DialogResult result = fbdlg.ShowDialog();
            if (result == DialogResult.OK)
                txtFolder.Text = fbdlg.SelectedPath;

            FillFilesList(txtFolder.Text);
            RefreshList();
        }

        private void FillFilesList(string path)
        {
            try
            {
                ItemSet itemSet = VcUtil.GetFilesInDB(path);

                if (chkRecursive.Checked)
                {
                    AddRecursiveFiles(txtFolder.Text, itemSet);
                }
                else
                {
                    AddDirFiles(itemSet);
                }

                for (int i = 0; i < this.lstAddFiles.Items.Count; i++)
                {
                    CheckUncheckAll(true);
                }
            }
            catch (Exception ex)
            {
                logger.Error(ex.Message);
            }
        }

        // Uncheck all listed files
        private void CheckUncheckAll(bool check)
        {
            for(int i = 0; i < this.lstAddFiles.Items.Count; i++)
            {
                this.lstAddFiles.Items[i].Checked = check;
            } 
        }

        // Check all listed files.
        private void btnCheckAll_Click(object sender, EventArgs e)
        {
            CheckUncheckAll(true);
        }

        // Uncheck all listed files
        private void btnUncheckAll_Click(object sender, EventArgs e)
        {
            CheckUncheckAll(false);
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        // Add all files under the specified folder
        private void AddDirFiles(ItemSet itemSet)
        {
            System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(txtFolder.Text);
            FileInfo[] files = dir.GetFiles();
            DirectoryInfo[] dirs = dir.GetDirectories();
            FileInfo[] filteredFiles = FilterFiles(files, txtFolder.Text, itemSet);
        }

        // Add all files under the specified folder recursively
        private void AddRecursiveFiles(string path,ItemSet itemSet)
        {
            System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(path);
            DirectoryInfo[] dirs = dir.GetDirectories();
            
            FileInfo[] newfiles = dir.GetFiles();

            FilterFiles(newfiles,txtProject.Text, itemSet);
            
            foreach (DirectoryInfo di in dirs)
            {
                AddRecursiveFiles(di.FullName, itemSet);
            }
        }

        // To Finish, we need to filter the already existing files on the server.
        private FileInfo[] FilterFiles(FileInfo[] files, string path, ItemSet itemSet)
        {
            FileInfo[] filteredFiles = new FileInfo[files.Length];
            VcLib.ExtensionsManager exts = new ExtensionsManager();
            IDictionary<string, bool> dics = exts.LoadFromXML(this.projectPath);

            try
            {
                bool found = false;
                string fileName;
                int nbFilteredFiles = 0;

                foreach (FileInfo file in files)
                {
                    found = false;
                    foreach (Item item in itemSet.Items)
                    {

                        fileName = stripString(file.FullName, item);

                        if (item.ServerItem.EndsWith(fileName))
                        {
                            found = true;
                            continue;
                        }
                    }
                    if (!found)
                    {
                        //Set of extension
                        bool isChecked;
                        if (!(dics.TryGetValue(file.Extension.ToLower(), out isChecked) && isChecked))
                        {
                            int nb = this.lstAddFiles.Items.Count;
                            AddOneFile(file);
                            filteredFiles[nbFilteredFiles] = file;
                            nbFilteredFiles++;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                this.logger.Error(ex.Message);
            }             
            return filteredFiles;
        }

        // transform fullFilePath : c:\\work\\projectname\\dir\\dir\\file.cs
        // to server path         : Dir/dir/File.cs
        private string stripString(string fullFilePath, Item item)
        {
            int nbCharTokeep;
            int nbCharStrip;
            string strResult;           
            int serverPathLenght = item.ServerItem.Length;

            try
            {
                // keep all chars after "$/ProjectName/
                nbCharTokeep = serverPathLenght - (this.txtProject.Text.Length + 3); //2 caracters for "$/" & 1 for the last /


                //TODO refactor stripstring
                if (nbCharTokeep < 0)
                    return "nbCharToKeepMinus";

                //localPath c:/work/projectname/dir/dir/file.cs  36 char
                nbCharStrip = fullFilePath.Length - nbCharTokeep;

                //remove nbChar from the begining
                strResult = fullFilePath.Substring(nbCharStrip);

                //Windows use \\ to separate folder and tfs server use / so we replace
                strResult = strResult.Replace('\\', '/');
                
                //return Dir/dir/File.ext
                return strResult;
            }
            catch
            {
                throw;
            }
        }

        private void chkRecursive_CheckedChanged(object sender, EventArgs e)
        {
            RefreshList();
        }

        private void AddOneFile(FileInfo file)
        {
            lstAddFiles.SmallImageList = imageList1;
            lstAddFiles.View = View.SmallIcon;

            ListViewItem lvi = new ListViewItem();
            ListViewItem.ListViewSubItem lvsi = new ListViewItem.ListViewSubItem();
            Icon iconForFile = SystemIcons.WinLogo;
            iconForFile = Icon.ExtractAssociatedIcon(file.FullName);

            if (!imageList1.Images.ContainsKey(file.Extension))
            {
                iconForFile = System.Drawing.Icon.ExtractAssociatedIcon(file.FullName);
                imageList1.Images.Add(file.Extension, iconForFile);
            }

            lvi.ImageKey = file.Extension;
            lvi.Checked = true;
            lvsi.Text = file.FullName;

            lvi.SubItems.Add(lvsi);
            this.lstAddFiles.Items.Add(lvi);
        }

        private void SetListView()
        {
            ColumnHeader colHead;

            colHead = new ColumnHeader();
            colHead.Text = "Select";
            colHead.Width = 45;
            this.lstAddFiles.Columns.Add(colHead);

            colHead = new ColumnHeader();
            colHead.Text = "File";
            colHead.Width = 700;
            this.lstAddFiles.Columns.Add(colHead);
        }

        // Add all checked files to the specified project
        private void btnOK_Click(object sender, EventArgs e)
        {
            try
            {
                int result;
                int size = this.lstAddFiles.CheckedItems.Count;
                string[] files = new string[size];

                if (size == 0)
                {
                    this.logger.Error("No file(s) selected");
                    return;
                }

                for (int i = 0; i < size; i++)
                {
                    files[i] = this.lstAddFiles.CheckedItems[i].SubItems[1].Text;
                }

                this.logger.Info("Starting to add files");
                result = VcUtil.AddFiles(this.txtFolder.Text, files);
                if (result == 1)
                    this.logger.ServerInfo(result.ToString() + " File successfully added!");
                else if(result > 1)
                    this.logger.ServerInfo(result.ToString() + " Files successfully added!");
                this.logger.Info("Do a CheckIn to save the changes");
                this.Close();
            }
            catch (Exception ex)
            {
                this.logger.Error(ex.Message);
            }
        }

        //Simulate the CheckOnClick of the checkBox
        private void lstAddFiles_Click(object sender, EventArgs e)
        {
            try
            {
                if (this.lstAddFiles.SelectedItems.Count > 0)
                {
                    this.lstAddFiles.SelectedItems[0].Checked = !this.lstAddFiles.SelectedItems[0].Checked;
                }
            }
            catch (Exception ex)
            {
                logger.DebugInfo(ex.Message);
            }
        }

        public void RefreshList()
        {
            this.logger.Info("Start refresh");
            this.lstAddFiles.Clear();
            SetListView();
            this.lstAddFiles.BeginUpdate();

            FillFilesList(txtFolder.Text);
            
            this.lstAddFiles.EndUpdate();
            this.lstAddFiles.Refresh();
            this.lstAddFiles.View = View.Details;
            this.logger.Info("Refresh done, " + this.lstAddFiles.Items.Count + " new file(s) found!");
        }
       
        private void btnExcludedExtension_Click(object sender, EventArgs e)
        {
            Form filterExtensions = new FilterExtensions(txtFolder.Text, this);
            filterExtensions.MdiParent = this.ParentForm;
            //cannot use the splitpanel from he child of the MainForm
            //use of getter to get the MainForm.splitContainer1.Panel1
            ((MainForm)this.ParentForm).GetMainPanel.Controls.Add(filterExtensions);
            filterExtensions.Dock = DockStyle.Fill;
            filterExtensions.Show();
        }
    }
}